#!/bin/bash
{
	#////////////////////////////////////
	# DietPi Backup
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - Location: /boot/dietpi/dietpi-backup
	# - Allows for a complete system back and restore of the linux filesystem (/)
	#
	# Usage:
	# - dietpi-backup -1 = Restore
	# - dietpi-backup    = Menu
	# - dietpi-backup  1 = Backup
	#
	# $2 = optional directory location to use with backup/restore input:
	# - dietpi-backup -1 /mnt/MyDirectoryTarget = Restore
	# - dietpi-backup  1 /mnt/MyDirectoryTarget = Backup
	#////////////////////////////////////

	# Import DietPi-Globals --------------------------------------------------------------
	. /boot/dietpi/func/dietpi-globals
	readonly G_PROGRAM_NAME='DietPi-Backup'
	G_CHECK_ROOT_USER
	G_CHECK_ROOTFS_RW
	G_INIT
	# Import DietPi-Globals --------------------------------------------------------------

	# Grab input
	[[ $1 =~ ^-?1$ ]] && INPUT=$1 || INPUT=0

	#/////////////////////////////////////////////////////////////////////////////////////
	# Backup System
	#/////////////////////////////////////////////////////////////////////////////////////
	readonly FP_LOG='/var/log/dietpi-backup.log'

	# Backup Filepaths
	FP_SOURCE='/'
	FP_TARGET='/mnt/dietpi-backup'

	# File applied to successful backups, stored in "$FP_TARGET/$FP_STATS"
	readonly FP_STATS='.dietpi-backup_stats'

	# Include/exclude file
	readonly FP_FILTER='.dietpi-backup_filter_inc_exc'
	readonly FP_FILTER_CUSTOM='/boot/dietpi/.dietpi-backup_inc_exc'

	# rsync options
	# - Backup: Delete files in target which are not present in source, or excluded
	readonly aRSYNC_RUN_OPTIONS_BACKUP=('-aH' '--info=name0' '--info=progress2' '--delete-excluded' "--exclude-from=$FP_FILTER")
	# - Restore: Delete files in target which are not present in source, but after the transfer has finished, and leave excluded files untouched
	readonly aRSYNC_RUN_OPTIONS_RESTORE=('-aH' '--info=name0' '--info=progress2' '--delete-after' "--exclude-from=$FP_FILTER")
	readonly aRSYNC_LOGGING_OPTIONS=('-v' "--log-file=$FP_LOG")

	# Date format for logs
	Print_Date(){ date '+%Y-%m-%d_%T'; }

	# rsync already running error: $1=Backup/Restore
	Error_Rsync_Already_Running(){

		G_DIETPI-NOTIFY 1 'Another rsync process is already running.'
		echo -e "$1 failed: $(Print_Date). rsync is already running." >> "$FP_TARGET/$FP_STATS"
		G_WHIP_MSG "$1 Error:\n\nA $1 could not be started as rsync is already running."
		/boot/dietpi/dietpi-services start

	}

	Check_Supported_Directory_Location(){

		# Check location contains /mnt/
		if [[ $FP_TARGET == '/mnt/'* ]]; then

			# Check file system type. Create directory temporarily, if necessary.
			if [[ ! -d $FP_TARGET ]]
			then
				G_EXEC mkdir -p "$FP_TARGET"
				local fs_type=$(df -T "$FP_TARGET" | mawk 'NR==2 {print $2}')
				G_EXEC rmdir "$FP_TARGET"
			else
				local fs_type=$(df -T "$FP_TARGET" | mawk 'NR==2 {print $2}')
			fi

			for i in 'ext4' 'ext3' 'ext2' 'nfs' 'nfs4' 'btrfs' 'f2fs' 'xfs' 'zfs'
			do
				[[ $fs_type == "$i" ]] || continue
				return 0
			done

			# Not supported
			G_DIETPI-NOTIFY 1 "Filesystem type $fs_type not supported in $FP_TARGET"
			G_WHIP_MSG "Filesystem type not supported:\n\n$FP_TARGET has a filesystem type of $fs_type, which is not supported.\n\nThe filesystem type must be ext2/3/4, F2FS, Btrfs, XFS or ZFS for symlink and POSIX permissions compatibilities."


		# Not inside /mnt
		else

			G_DIETPI-NOTIFY 1 "Target directory is not inside /mnt ($FP_TARGET)"
			G_WHIP_MSG "Directory not supported:\n- $FP_TARGET\n\nThe location must be inside the /mnt/* directory.\n - E.g.: /mnt/dietpi-backup"

		fi

		return 1

	}

	Create_Filter_Include_Exclude(){

		cat << _EOF_ > $FP_FILTER
# Backup data, log and config
- $FP_TARGET/
- $FP_LOG
- $FP_SETTINGS
# RAM dirs
- /dev/
- /proc/
- /run/
- /sys/
- /tmp/
# Swap files
- /var/swap
- .swap*
# Fake RTC timestamp
- /etc/fake-hwclock.data
# Unlinked inodes
- /lost+found/
# APT cache
- /var/cache/apt/*
_EOF_

		# Add users filter list
		[[ -f $FP_FILTER_CUSTOM ]] && cat $FP_FILTER_CUSTOM >> $FP_FILTER

	}

	Run_Backup(){

		G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Backup'

		# Check valid FS
		Check_Supported_Directory_Location || return 1

		# Generate target dir
		G_EXEC_NOHALT=1 G_EXEC mkdir -p "$FP_TARGET/data"

		# Error: Unable to create target folder.
		if [[ ! -d $FP_TARGET/data ]]; then

			G_WHIP_MSG "Backup failed:\n\nUnable to create $FP_TARGET/data"

		else

			/boot/dietpi/dietpi-services stop

			# Check if rsync is already running, while the daemon should have been stopped above
			pgrep 'rsync' &> /dev/null && { Error_Rsync_Already_Running 'Backup'; return 1; }

			# Install required rsync if missing
			G_AG_CHECK_INSTALL_PREREQ rsync

			# Generate Exclude/Include lists
			Create_Filter_Include_Exclude

			# Check for sufficient free space
			local old_backup_size=$(du -sB1 "$FP_TARGET/data" | mawk '{print $1}') # Actual disk usage in bytes
			# - Dry run to obtain transferred data size
			rsync --dry-run --stats "${aRSYNC_RUN_OPTIONS_BACKUP[@]}" "$FP_SOURCE" "$FP_TARGET/data/" > .dietpi-backup_result
			local new_backup_size=$(grep -m1 '^Total file size:' .dietpi-backup_result | sed 's/[^0-9]*//g') # Apparent data size without block size related overhead
			local total_file_count=$(mawk '/^Number of files:/{print $6;exit}' .dietpi-backup_result | sed 's/[^0-9]*//g')
			local total_folder_count=$(mawk '/^Number of files:/{print $8;exit}' .dietpi-backup_result | sed 's/[^0-9]*//g')
			rm .dietpi-backup_result
			local target_fs_blocksize=$(stat -fc '%s' "$FP_TARGET/data")
			new_backup_size=$(( $new_backup_size + ( $total_file_count + $total_folder_count ) * $target_fs_blocksize )) # Add one block size for each file + dir as worst case result
			local end_result=$(( ( $new_backup_size - $old_backup_size ) / 1024**2 + 1 )) # bytes => MiB rounded up
			# - Perform check
			if ! G_CHECK_FREESPACE "$FP_TARGET/data" $end_result; then

				G_WHIP_BUTTON_OK_TEXT='Ignore'
				G_WHIP_BUTTON_CANCEL_TEXT='Exit'
				if ! G_WHIP_YESNO 'The backup target location appears to have insufficient free space to successfully finish the backup.
However, this check is a rough estimation in reasonable time, thus it could be marginally incorrect.
\nWould you like to override this warning and continue with the backup?'; then

					echo -e "Backup cancelled due to insufficient free space    : $(Print_Date)" >> "$FP_TARGET/$FP_STATS"
					/boot/dietpi/dietpi-services start
					return 1

				fi

			fi

			G_DIETPI-NOTIFY 2 "Backup to $FP_TARGET in progress, please wait..."

			# Init log file
			echo -e "Backup log from $(Print_Date)\n" > $FP_LOG

			rsync "${aRSYNC_RUN_OPTIONS_BACKUP[@]}" "${aRSYNC_LOGGING_OPTIONS[@]}" "$FP_SOURCE" "$FP_TARGET/data/"
			EXIT_CODE=$?

			/boot/dietpi/dietpi-services start

			G_DIETPI-NOTIFY -1 $EXIT_CODE "$G_PROGRAM_NAME: Backup"
			if (( $EXIT_CODE == 0 )); then

				echo -e "Backup completed    : $(Print_Date)" >> "$FP_TARGET/$FP_STATS"
				G_WHIP_MSG "Backup completed:\n - $FP_TARGET"

			else

				G_WHIP_MSG "Backup failed:\n - $FP_TARGET\n\nYou will see the log file on the next screen. Please check it for information and/or errors."

			fi

			log=1 G_WHIP_VIEWFILE $FP_LOG

		fi

	}

	# When restoring a backup, assure that either the UUIDs stored in the backup fstab/boot config matches the current system drive, or that we know all relevant files to adjust afterwards.
	Check_UUIDs()
	{
		UPDATE_UUIDs=0 UPDATE_GRUB=0 UPDATE_RPI=0 UPDATE_ARMBIAN=0 UPDATE_ODROID=0 UPDATE_UBOOT=0
		UUID_ROOT=$(findmnt -Ufnro UUID -M /)
		PARTUUID_ROOT=$(findmnt -Ufnro PARTUUID -M /)

		# If the current rootfs' UUID or PARTUUID can be found in the the backups fstab, it can be assumed that it was created from the same drives.
		grep -q "^UUID=${UUID_ROOT}[[:blank:]]" "$FP_TARGET/data/etc/fstab" || grep -q "^PARTUUID=${PARTUUID_ROOT}[[:blank:]]" "$FP_TARGET/data/etc/fstab" && return 0

		UPDATE_UUIDs=1

		# Else check if we know how to adjust the boot config after the backup has been restored.
		# - x86_64
		if (( $G_HW_ARCH == 10 )) && command -v update-grub > /dev/null
		then
			UPDATE_GRUB=1

		# - RPi
		elif (( $G_HW_MODEL < 10 )) && [[ -f $FP_TARGET/data/boot/cmdline.txt ]]
		then
			UPDATE_RPI=1

		# - Armbian
		elif [[ -f $FP_TARGET/data/boot/armbianEnv.txt ]]
		then
			UPDATE_ARMBIAN=1

		# - Odroids / classic U-Boot
		elif [[ -f $FP_TARGET/data/boot/boot.ini ]]
		then
			UPDATE_ODROID=1

		# - Modern U-Boot
		elif [[ -f $FP_TARGET/data/boot/boot.cmd ]] && command -v mkimage > /dev/null
		then
			UPDATE_UBOOT=1

		# - Else we cannot assure that the restored image will boot.
		else
			# Let user decide, but default to "no"
			G_WHIP_YESNO '[WARNING] UUIDs of the backup and the current system differ
\nThe file systems unique identifiers, usually used to mount the drives at boot, seem to differ between the backup and the current system.
\nThis usually indicates that you try to restore an old backup onto a newly flashed DietPi system.
\nMoreover are we not able to find the boot configuration, where those UUIDs would need to be adjusted, to assure that the system will boot.
\nWe hence do not recommend to restore this backup on this system. If you continue, you will need to assure yourself that fstab and boot configurations match the UUIDs, else the system may not boot.
\nDo you want to restore this backup?' && return 0 || return 1
		fi

		G_WHIP_DEFAULT_ITEM='ok' G_WHIP_YESNO '[WARNING] UUIDs of the backup and the current system differ
\nThe file systems unique identifiers, usually used to mount the drives at boot, seem to differ between the backup and the current system.
\nThis usually indicates that you try to restore an old backup onto a newly flashed DietPi system.
\nBut we were able to find the boot configuration, where those UUIDs would need to be adjusted, to assure that the system will boot.
\nIt should be hence safe to restore this backup, but if the UUIDs were used elsewhere, you might need to adjust it manually.
\nDo you want to restore this backup?' && return 0 || return 1
	}

	Update_UUIDs()
	{
		# fstab
		while read -r mountpoint
		do
			[[ $mountpoint ]] || continue
			local uuid=$(findmnt -Ufnro UUID -M "$mountpoint")
			[[ $uuid ]] && G_EXEC sed -i "\|[[:blank:]]${mountpoint}[[:blank:]]|s|^[[:blank:]]*UUID=[^[:blank:]]*|UUID=$uuid|" /etc/fstab
			local partuuid=$(findmnt -Ufnro PARTUUID -M "$mountpoint")
			[[ $partuuid ]] && G_EXEC sed -i "\|[[:blank:]]${mountpoint}[[:blank:]]|s|^[[:blank:]]*PARTUUID=[^[:blank:]]*|PARTUUID=$partuuid|" /etc/fstab

		done < <(lsblk -no MOUNTPOINT "$(lsblk -npo PKNAME "$G_ROOTFS_DEV")")

		# boot configs
		# - x86_64
		if (( UPDATE_GRUB == 1 ))
		then
			G_EXEC update-grub
			command -v update-tirfs > /dev/null && G_EXEC update-tirfs && return
			command -v update-initramfs > /dev/null && G_EXEC update-initramfs -u

		# - RPi
		elif (( UPDATE_RPI == 1 ))
		then
			G_EXEC sed -Ei "s/(^|[[:blank:]])root=[^[:blank:]]*/\1root=PARTUUID=$PARTUUID_ROOT/" /boot/cmdline.txt

		# - Armbian
		elif (( UPDATE_ARMBIAN == 1 ))
		then
			grep -q '^[[:blank:]]*rootdev=UUID=' /boot/armbianEnv.txt && G_CONFIG_INJECT 'rootdev=UUID=' "rootdev=UUID=$UUID_ROOT" /boot/armbianEnv.txt && return
			grep -q '^[[:blank:]]*rootdev=PARTUUID=' /boot/armbianEnv.txt && G_CONFIG_INJECT 'rootdev=PARTUUID=' "rootdev=PARTUUID=$PARTUUID_ROOT" /boot/armbianEnv.txt

		# - Odroids / classic U-Boot
		elif (( UPDATE_ODROID == 1 ))
		then
			G_EXEC sed -Ei "s/(\"|root=)UUID=[^[:blank:]\"]*/\1UUID=$UUID_ROOT/" /boot/boot.ini
			G_EXEC sed -Ei "s/(\"|root=)PARTUUID=[^[:blank:]\"]*/\1PARTUUID=$PARTUUID_ROOT/" /boot/boot.ini

		# - Modern U-Boot
		elif (( UPDATE_UBOOT == 1 ))
		then
			G_EXEC sed -Ei "s/(\"|root=)UUID=[^[:blank:]\"]*/\1UUID=$UUID_ROOT/" /boot/boot.cmd
			G_EXEC sed -Ei "s/(\"|root=)PARTUUID=[^[:blank:]\"]*/\1PARTUUID=$PARTUUID_ROOT/" /boot/boot.cmd
			G_EXEC mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr
		fi
	}

	Run_Restore(){

		G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" 'Restore'

		# Check valid FS
		Check_Supported_Directory_Location || return 1

		# Error: Backup not found
		if [[ ! -f $FP_TARGET/$FP_STATS ]]; then

			G_WHIP_MSG "Restore failed:\n\n$FP_TARGET/$FP_STATS does not exist\n\nHave you created a backup?"

		# Restore
		else

			Check_UUIDs || return 1

			/boot/dietpi/dietpi-services stop

			# Check if rsync is already running, while the daemon should have been stopped above
			pgrep 'rsync' &> /dev/null && { Error_Rsync_Already_Running 'Restore'; return 1; }

			# Install required rsync if missing
			G_AG_CHECK_INSTALL_PREREQ rsync

			# Generate Exclude/Include lists
			Create_Filter_Include_Exclude

			G_DIETPI-NOTIFY 2 "Restore from $FP_TARGET in progress, please wait..."

			# Init log file
			echo -e "Restore log from $(Print_Date)\n" > $FP_LOG

			rsync "${aRSYNC_RUN_OPTIONS_RESTORE[@]}" "${aRSYNC_LOGGING_OPTIONS[@]}" "$FP_TARGET/data/" "$FP_SOURCE"
			EXIT_CODE=$?

			hash -d # Clear PATH cache
			(( $UPDATE_UUIDs )) && Update_UUIDs

			/boot/dietpi/dietpi-services start

			G_DIETPI-NOTIFY -1 $EXIT_CODE "$G_PROGRAM_NAME: Restore"
			if (( $EXIT_CODE == 0 )); then

				echo -e "Restore completed    : $(Print_Date)" >> "$FP_TARGET/$FP_STATS"
				G_WHIP_MSG "Restore completed:\n - $FP_TARGET\n\nNB: A Reboot is highly recommended."

			else

				G_WHIP_MSG "Restore failed:\n - $FP_TARGET\n\nYou will see the log file on the next screen. Please check it for information and/or errors."

			fi

			log=1 G_WHIP_VIEWFILE $FP_LOG

		fi

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Settings
	#/////////////////////////////////////////////////////////////////////////////////////
	readonly FP_SETTINGS='/boot/dietpi/.dietpi-backup_settings'

	Write_Settings_File(){ echo "FP_TARGET=$FP_TARGET" > $FP_SETTINGS; }

	Read_Settings_File(){ [[ -f $FP_SETTINGS ]] && . $FP_SETTINGS; }

	#/////////////////////////////////////////////////////////////////////////////////////
	# Menus
	#/////////////////////////////////////////////////////////////////////////////////////
	MENU_LASTITEM='Help' # Select "Help" by default
	TARGETMENUID=0 # Main menu
	EXIT_CODE=-1 # Relevant for automated calls "dietpi-backup -1" and "dietpi-backup 1" e.g. via G_PROMPT_BACKUP

	# TARGETMENUID=0
	Menu_Main(){

		local backup_last_completed='Backup not found. Please create one.'

		G_WHIP_MENU_ARRAY=()
		G_WHIP_MENU_ARRAY+=('' '●─ Info ')
		G_WHIP_MENU_ARRAY+=('Help' "What does $G_PROGRAM_NAME do?")
		G_WHIP_MENU_ARRAY+=('' '●─ Options ')
		G_WHIP_MENU_ARRAY+=('Location' ': Change where your backup will be saved and restored from.')
		G_WHIP_MENU_ARRAY+=('Filter' ': Modify include/exclude filter for backups.')
		if [[ -f $FP_TARGET'/'$FP_STATS ]]; then

			G_WHIP_MENU_ARRAY+=('Delete' ": Remove backup ($FP_TARGET)")
			backup_last_completed=$(grep 'ompleted' "$FP_TARGET/$FP_STATS" | tail -1)

		fi
		G_WHIP_MENU_ARRAY+=('' '●─ Run ')
		G_WHIP_MENU_ARRAY+=('Backup' 'Create (or update) a backup of this device.')
		G_WHIP_MENU_ARRAY+=('Restore' 'Restore this device from a previous backup.')

		G_WHIP_DEFAULT_ITEM=$MENU_LASTITEM
		G_WHIP_BUTTON_CANCEL_TEXT='Exit'
		if G_WHIP_MENU "Current backup and restore location:\n - $FP_TARGET\n - $backup_last_completed"; then

			MENU_LASTITEM=$G_WHIP_RETURNED_VALUE

			case "$G_WHIP_RETURNED_VALUE" in

				'Location') TARGETMENUID=1;;

				'Filter') nano $FP_FILTER_CUSTOM;;

				'Help') G_WHIP_MSG "DietPi-Backup is a program that allows you to Backup and Restore your DietPi system.
\nIf you have broken your system, or want to reset your system to an earlier date, this can all be done with DietPi-Backup.
\nSimply choose a location where you want to save and restore your backups from, then, select Backup or Restore.
\nMore information: https://dietpi.com/docs/dietpi_tools/#dietpi-backup-backuprestore";;

				'Delete') G_WHIP_YESNO "Do you wish to DELETE the following backup?\n - $FP_TARGET" && G_EXEC_NOEXIT=1 G_EXEC rm -R "$FP_TARGET";;

				'Backup') G_WHIP_YESNO "The system will be backed up to:\n - $FP_TARGET\n\nDo you wish to continue and start the backup?" && Run_Backup;;

				'Restore') G_WHIP_YESNO "The system will be restored from:\n - $FP_TARGET\n\nDo you wish to continue and start the restore?" && Run_Restore;;

			esac

		else

			Menu_Exit

		fi

	}

	Menu_Exit(){ G_WHIP_SIZE_X_MAX=50 G_WHIP_YESNO "Exit $G_PROGRAM_NAME?" && TARGETMENUID=-1 EXIT_CODE=0; }

	# TARGETMENUID=1
	Menu_Set_Directory(){

		G_WHIP_MENU_ARRAY=(

			'Search' ': Find previous backups in /mnt/*'
			'List' ': Select from a list of available mounts/drives'
			'Manual' ': Manually type a directory to use'

		)

		if G_WHIP_MENU "Please select the location where the backup will be saved, and restored from.\n\nYour current location:\n$FP_TARGET"; then

			local current_directory=$FP_TARGET

			case "$G_WHIP_RETURNED_VALUE" in

				'Search')

					G_DIETPI-NOTIFY 2 'Searching /mnt/* for previous backups, please wait...'
					local alist=()
					mapfile -t alist < <(find /mnt -type f -name "$FP_STATS")

					# Do we have any results?
					if [[ ${alist[0]} ]]; then

						# Create List for Whiptail
						G_WHIP_MENU_ARRAY=()
						for i in "${alist[@]}"
						do

							local last_backup_date=$(sed -n '/ompleted/s/^.*: //p' "$i" | tail -1) # Date of last backup for this backup
							local backup_directory=${i%/$FP_STATS} # Backup directory (minus the backup file), that we can use for target backup directory.
							G_WHIP_MENU_ARRAY+=("$backup_directory" ": $last_backup_date")

						done

						G_WHIP_MENU 'Please select a previous backup to use:' || return
						FP_TARGET=$G_WHIP_RETURNED_VALUE

					else

						G_WHIP_MSG 'No previous backups were found in /mnt/*'
						return

					fi

				;;

				'Manual')

					G_WHIP_DEFAULT_ITEM=$FP_TARGET
					G_WHIP_INPUTBOX 'Please enter the filepath to your directory.\nE.g.: /mnt/dietpi-backup\n - Must be located inside /mnt/*\n - Must be a symlink and UNIX permissions compatible file system, like ext4, Btrfs, F2FS or valid NFS mount' || return
					FP_TARGET=$G_WHIP_RETURNED_VALUE

				;;

				'List')

					/boot/dietpi/dietpi-drive_manager 1 || return
					FP_TARGET=$(</tmp/dietpi-drive_manager_selmnt)
					rm /tmp/dietpi-drive_manager_selmnt

					[[ $FP_TARGET == '/' ]] && FP_TARGET='/mnt'
					FP_TARGET+='/dietpi-backup'

				;;

			esac

			# If not supported, reset directory target to previous
			Check_Supported_Directory_Location || FP_TARGET=$current_directory

		else

			TARGETMENUID=0 # Return to main menu

		fi

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Main Loop
	#/////////////////////////////////////////////////////////////////////////////////////
	# Read settings
	Read_Settings_File

	# $2 Optional directory input
	[[ $2 ]] && FP_TARGET=$2

	# Create default filter file, if not yet present
	[[ -f $FP_FILTER_CUSTOM ]] || cat << '_EOF_' > $FP_FILTER_CUSTOM
# DietPi-Backup include/exclude filter

# Prefix "-" exclude items, "+" include items which would match a wildcard exclude rule.
# Suffix "/" match directories only, no files or symlinks.
# Using wildcard "*" matches any item name or part of it.
# Since the list is processed from top to bottom and the first match defines the result,
#   includes need to be defined before their wildcard exclude rule
#   and in case excludes before their wildcard include rule.
# Symlinks are handled as such and never processed recursively.
# Excluded directories are not processed recursively, so contained items cannot be included.
# Hence, to include items within an excluded directory:
# - Do not exclude the directory itself, but contained items via wildcard.
# - Define includes first, to override the wildcard exclude rule.
# - See the below default rules, how we exclude all items below /mnt
#   but include the dietpi_userdata directory, if it is no symlink.
# To prevent loops, the backup target dir, log and config are excluded internally.

+ /mnt/dietpi_userdata/
- /mnt/*
- /media/
_EOF_
	#-----------------------------------------------------------------------------
	# Run Backup
	if (( $INPUT == 1 )); then

		Run_Backup

	# Run Restore
	elif (( $INPUT == -1 )); then

		Run_Restore

	#-----------------------------------------------------------------------------
	# Run menu, if interactive
	elif (( $G_INTERACTIVE )); then

		until (( $TARGETMENUID < 0 ))
		do
			G_TERM_CLEAR

			if (( $TARGETMENUID == 1 )); then

				Menu_Set_Directory

			else

				Menu_Main

			fi
		done

		# Save settings
		Write_Settings_File

	fi
	#-----------------------------------------------------------------------------------
	exit $EXIT_CODE
	#-----------------------------------------------------------------------------------
}
